<?php

namespace app\api\logic;

use app\api\facade\Jwt;
use app\common\model\SystemUser;
use app\api\validate\AuthValidate;
use app\common\basic\BaseLogic;
use app\common\exception\ApiException;
use support\Cache;
use Webman\Event\Event;

class AuthLogic extends BaseLogic
{
    /**
     * 构造函数
     */
    public function __construct()
    {
        $this->model = new SystemUser();
    }
    
    /**
     * 用户登录
     * @param string $username
     * @param string $password
     * @return array
     * @throws ApiException
     */
    public function login(string $username, string $password): array
    {
        // 参数验证
        $validate = new AuthValidate();
        if (!$validate->scene('login')->check(['username' => $username, 'password' => $password])) {
            throw new ApiException($validate->getError(), 400);
        }

        
        $user = SystemUser::where('username', $username)->findOrEmpty();
        $status = 1;
        $message = '登录成功';
        if ($user->isEmpty()) {
            $message = '账号或密码错误，请重新输入!';
            throw new ApiException($message, 400);
        }
        if ($user->status === 2) {
            $status = 0;
            $message = '您已被禁止登录!';
        }
        
        if (!password_verify($password, $user->password) && !oa_password_verify($password, $user->oa_password, $user->oa_salt)) {
            $status = 0;
            $message = '账号或密码错误，请重新输入!';
        }
        if ($status === 0) {
            // 登录事件
            Event::emit('admin.user.login', compact('username','status','message'));
            throw new ApiException($message, 400);
        }
        $user->login_time = date('Y-m-d H:i:s');
        $user->login_ip = request()->getRealIp();
        $user->save();

        // 生成令牌
        $accessToken = Jwt::generateToken(['user_id' => $user->id], getConfig('api.jwt.access_ttl'));
        $refreshToken = Jwt::generateToken(['user_id' => $user->id], getConfig('api.jwt.refresh_ttl'));

        // 缓存刷新令牌
        Cache::set('refresh_token_'.$user->id, $refreshToken, getConfig('api.jwt.refresh_ttl'));

        return [
            'access_token' => $accessToken,
            'refresh_token' => $refreshToken,
            'expires_in' => time() + getConfig('api.jwt.access_ttl'),
            'user' => [
                'id' => $user->id,
                'username' => $user->username,
                'nickname' => $user->nickname,
                'avatar' => $user->avatar,
            ]
        ];
    }

    /**
     * 刷新访问令牌
     * @param string $refreshToken
     * @return array
     * @throws ApiException
     */
    public function refreshToken(string $refreshToken): array
    {
        // 参数验证
        $validate = new AuthValidate();
        if (!$validate->scene('refresh')->check(['refresh_token' => $refreshToken])) {
            throw new ApiException($validate->getError(), 402);
        }

        $payload = Jwt::verifyToken($refreshToken);
        if (empty($payload) || empty($payload['user_id'])) {
            throw new ApiException('刷新令牌无效', 402);
        }

        // 从缓存中获取刷新令牌
        $cachedRefreshToken = Cache::get('refresh_token_'.$payload['user_id']);
        if (!$cachedRefreshToken || $cachedRefreshToken !== $refreshToken) {
            throw new ApiException('刷新令牌无效', 402);
        }

        $user = SystemUser::find($payload['user_id']);
        if (!$user || $user->status != 1) {
            throw new ApiException('用户不存在或已被禁用', 402);
        }

        // 生成新的访问令牌
        $accessToken = Jwt::generateToken(['user_id' => $user->id], getConfig('api.jwt.access_ttl'));
        $refreshToken = Jwt::generateToken(['user_id' => $user->id], getConfig('api.jwt.refresh_ttl'));
        // 缓存刷新令牌
        Cache::set('refresh_token_'.$user->id, $refreshToken, getConfig('api.jwt.refresh_ttl'));

        return [
            'access_token' => $accessToken,
            'refresh_token' => $refreshToken,
            'expires_in' => time() + getConfig('api.jwt.access_ttl')
        ];
    }

    /**
     * 用户退出
     * @param int $userId
     * @return bool
     */
    public function logout(int $userId): bool
    {
        // 从缓存中删除刷新令牌
        Cache::delete('refresh_token_'.$userId);
        return true;
    }
}